<template>
  <div ref="outer" class="waterfall-flex" :style="{ gap: `${gap}px` }">
    <div v-for="c of column" :key="c" class="col" :style="{ gap: `${gap}px` }">
      <div v-for="item in group[c - 1]" :key="item[idKey]" class="cell">
        <div>
          <img :src="(item.posterImage || [])[0]?.imageResize200Url" style="width: 100%" />
          <p>{{ item.title }}</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts" generic="T">
  import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue';
  import type { VNode } from 'vue';

  defineSlots<{
    default?: (props: {
      item: any;
      column: number;
      columnCount: number;
      row: number;
      index: number;
    }) => VNode | VNode[] | Element | Element[];
  }>();

  const props = withDefaults(
    defineProps<{
      items: any[];
      column?: number;
      gap?: number;
      idKey?: keyof any;
      widthKey?: string;
      heightKey?: string;
    }>(),
    {
      column: 4,
      gap: 16,
      idKey: 'id' as keyof any,
      widthKey: 'width',
      heightKey: 'height',
    }
  );

  /* ---------- 状态 ---------- */
  const outer = ref<HTMLDivElement>();
  const heights = ref<number[]>([]);
  const containerWidth = ref(0);
  const group = ref<any[][]>([]);

  /* 计算单个项目的高度 */
  const calculateItemHeight = (item: any, columnWidth: number): number => {
    const width = item[props.widthKey] || item.posterImage?.[0]?.width;
    const height = item[props.heightKey] || item.posterImage?.[0]?.height;

    if (width && height) {
      // 根据列宽和图片原始宽高比计算高度
      return (columnWidth * height) / width;
    }

    // 如果没有宽高信息，使用默认高度
    return 200;
  };

  /* 最短列索引 */
  const minIndex = (currentHeights: number[]): number => {
    let idx = 0;
    for (let i = 1; i < currentHeights.length; i++) {
      if (currentHeights[i] < currentHeights[idx]) idx = i;
    }
    return idx;
  };

  /* 计算列宽 */
  const columnWidth = computed(() => {
    if (!containerWidth.value) return 0;
    return (containerWidth.value - props.gap * (props.column - 1)) / props.column;
  });

  /* 更新分组 */
  const updateGroup = () => {
    const col = props.column;
    const buckets: any[][] = Array.from({ length: col }, () => []);

    const tempHeights = Array(col).fill(0);

    // 按最短列策略分配所有项目
    props.items.forEach((item) => {
      const idx = minIndex(tempHeights);
      buckets[idx].push(item);

      // 计算项目高度并累加（包括间距）
      const itemHeight = calculateItemHeight(item, columnWidth.value);
      tempHeights[idx] += itemHeight + props.gap;
      console.log('temp', idx, tempHeights);

      //   console.log('temp', tempHeights);
    });

    group.value = buckets;
  };

  /* ---------- 容器宽度测量和更新 ---------- */
  const updateContainerWidth = () => {
    if (outer.value) {
      containerWidth.value = outer.value.offsetWidth;
    }
  };

  // 监听相关数据变化，触发更新
  watch(
    [() => props.items, () => props.column, () => props.gap, columnWidth],
    () => {
      updateGroup();
    },
    { immediate: true }
  );

  let ro: ResizeObserver | undefined;
  onMounted(() => {
    updateContainerWidth();

    ro = new ResizeObserver(() => {
      //   updateContainerWidth();
    });
    if (outer.value) {
      ro.observe(outer.value);
    }
  });

  onBeforeUnmount(() => ro?.disconnect());
</script>

<style>
  .waterfall-flex {
    display: flex;
  }
  .col {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
  }
  .cell {
    width: 100%;
  }
</style>
